feat: Oracle activity reporting — cross-project daily digest (v2.38.0)#18
Merged
Merged
Conversation
The Oracle can now produce a cross-project "what happened today" digest:
sessions, tool calls, edits, git mutations, and token/cost. Exposed as a
discovery tool (MCP + REST + OpenAPI + internal chat), a dedicated endpoint,
and a web-UI tab.
- ActivityReporter (oracle/services/activity_reporter.py): aggregates per-project
activity from .c3 JSONL (ActivityLog / SessionManager / EditLedger) for a UTC day
or since/until window; skips non-C3 projects without side effects; optional
best-effort Ollama narration (never fails the structured result).
- activity_report discovery tool (read tier) in TOOL_SPECS — one registry spec
auto-exposes it on REST, OpenAPI, and MCP. Dispatch wired through ChatEngine.
- GET /api/activity/digest endpoint + Activity tab in oracle.html (date picker,
totals cards, optional narrative, per-project breakdown).
- Tests: tests/test_activity_reporter.py + extended discovery/registry tests (28 pass).
- Docs: README, oracle-guide/{api-reference,discovery-api,changelog}.md, in-app
cli/guide/oracle.html tool table, CHANGELOG; version bump to 2.38.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds cross-project activity reporting to the Oracle, exposing a daily (UTC) digest of sessions, tool calls, edits/git mutations, and token/cost both as a Discovery tool (activity_report) and as a first-class Oracle UI/API feature.
Changes:
- Introduces
ActivityReporterto aggregate per-project.c3/*.jsonlartifacts into a structured digest, with optional best-effort LLM narration. - Exposes the digest via:
activity_reportinTOOL_SPECS,ChatEnginedispatch, and a newGET /api/activity/digestendpoint + “Activity” dashboard tab. - Adds/updates tests and documentation, and bumps the package version to
2.38.0.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_tool_registry.py | Verifies activity_report is read-tier and callable with empty args. |
| tests/test_oracle_discovery_api.py | Ensures the Discovery API lists and dispatches activity_report. |
| tests/test_activity_reporter.py | New unit tests for digest windowing, totals, filtering, non-C3 skipping, and narrate failure handling. |
| README.md | Documents the new activity digest surfaces (tool, endpoint, UI tab). |
| pyproject.toml | Version bump to 2.38.0. |
| oracle/services/tool_registry.py | Adds activity_report tool spec to the canonical tool catalog. |
| oracle/services/chat_engine.py | Wires activity_report into tool defs, init injection, and dispatcher. |
| oracle/services/activity_reporter.py | Implements cross-project digest aggregation + optional narration. |
| oracle/oracle.html | Adds an “Activity” tab and client-side rendering of the digest. |
| oracle/oracle_server.py | Initializes ActivityReporter and adds GET /api/activity/digest. |
| oracle-guide/discovery-api.md | Adds activity_report to the read-tier tool list. |
| oracle-guide/changelog.md | Changelog entry describing activity reporting. |
| oracle-guide/api-reference.md | Adds API reference docs for GET /api/activity/digest. |
| cli/guide/oracle.html | Updates in-app guide tool table to include activity_report. |
| cli/c3.py | Version bump to 2.38.0. |
| CHANGELOG.md | Adds 2.38.0 release notes for Oracle activity reporting. |
Comment on lines
+60
to
+64
| for proj in self._target_projects(project_path): | ||
| pr = self._report_project(proj, lo, hi) | ||
| if (pr["tool_calls"] or pr["edits"] or pr["git_mutations"] | ||
| or pr["sessions"] or pr["decisions"]): | ||
| proj_reports.append(pr) |
Comment on lines
+143
to
+146
| try: | ||
| counts: dict[str, int] = {} | ||
| for e in ActivityLog(path).get_recent(limit=10000, since=lo, until=hi): | ||
| etype = e.get("type", "unknown") |
Comment on lines
+171
to
+174
| # Token / cost from hook-captured session stats. | ||
| for st in sm.get_session_stats(500): | ||
| ts = st.get("ts", "") | ||
| if ts and lo <= ts <= hi: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the Oracle an activity reporter: a cross-project "what happened today" digest aggregating sessions, tool calls, edits, git mutations, and token/cost. Returned as structured JSON with an optional LLM-narrated prose summary.
Previously the Oracle could expose code/memory intelligence to external LLMs but had no way to report user activity or sessions. The data already existed per project (
.c3/activity_log.jsonl,.c3/session_stats.jsonl,.c3/edit_ledger.jsonl) but was siloed and only surfaced one project at a time.What's included
ActivityReporter(oracle/services/activity_reporter.py) — aggregates per-project activity from.c3JSONL viaActivityLog/SessionManager/EditLedgerfor a UTC day (orsince/untilwindow), across all registered projects or one viaproject_path. Reads directly off disk (no C3Runtime build); skips non-C3 projects without side effects. Optionalnarrate=trueadds a best-effort Ollama prose digest (never fails the structured result).activity_reportdiscovery tool (read tier) inTOOL_SPECS. The registry is the single source of truth, so one spec auto-exposes the tool on REST (/api/discovery/call), OpenAPI, MCP, and the internal Oracle chat. Dispatch wired throughChatEngine.GET /api/activity/digestendpoint (date/since/until/project/narrate) + an Activity tab inoracle.html(date picker, totals cards, optional narrative, per-project breakdown table).Docs
README,
oracle-guide/api-reference.md,oracle-guide/discovery-api.md,oracle-guide/changelog.md, the in-appcli/guide/oracle.htmltool table, and CHANGELOG.Testing
tests/test_activity_reporter.py(windowing, totals, single-project filter, non-C3 skip, narrate-error); extendedtest_oracle_discovery_api.py+test_tool_registry.py.oracle_serverimports cleanly..c3data: today's digest returned 192 tool calls, 43 edits, 35 git mutations. (Sessions/tokens are 0 here — no session formally saved today and the token-capturing Stop hook isn't active — correct behavior.)🤖 Generated with Claude Code